﻿//  Copyright (c) 2011 Ray Liang (http://www.dotnetage.com)
//  Licensed MIT: http://www.opensource.org/licenses/mit-license.php

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DNA.Mvc.Installation;
using DNA.OpenAPI.BlogML;
using System.Web.Security;
using System.IO;
using DNA.Utility;

namespace DNA.Mvc.Publishing
{
    public class BlogMLInstaller : InstallerBase
    {
        private IPubContext pubContext;

        public BlogMLInstaller(IPubContext context)
        {
            pubContext = context;
        }

        private IDictionary<string, Category> categoryReferences = new Dictionary<string, Category>();

        public override string Name
        {
            get { return "bml"; }
        }

        public override void Execute(InstallationContext context)
        {
            var configDoc = GetConfiguationDocument();
            BlogMLBlog blog;
            var website = context.Data["Web.Name"].ToString();
            if (configDoc != null)
            {
                if (configDoc.DocumentElement.HasAttribute("src"))
                {
                    var filename = ExecutionPath + "\\" + configDoc.DocumentElement.Attributes["src"].Value;
                    if (File.Exists(filename))
                    {
                        blog = XmlSerializerUtility.DeserializeFormXmlFile<BlogMLBlog>(filename);
                        CreateBlog(website, blog);
                    }
                }
                else
                {
                    if (!string.IsNullOrEmpty(configDoc.DocumentElement.InnerXml))
                    {
                        blog = XmlSerializerUtility.DeserializeFromXmlText<BlogMLBlog>(configDoc.DocumentElement.InnerXml);
                        CreateBlog(website, blog);
                    }
                }
            }
        }

        private void CreateBlog(string name, BlogMLBlog blog)
        {
            var category = pubContext.Categories.Find(name);

            if (category == null)
            {
                category = new Category()
                {
                    Title = blog.Title,
                    Path = name,
                    LastPosted = new DateTime(1800, 1, 1)
                };

                if (!string.IsNullOrEmpty(blog.SubTitle))
                    category.Description = blog.SubTitle;

                pubContext.Categories.Create(category);
                pubContext.SaveChanges();
            }
            CreateCategories(category, blog.Categories);

            CreateAuthors(blog.Authors);
        }

        private void CreateAuthors(IEnumerable<BlogMLAuthor> authors)
        {
            foreach (var author in authors)
            {
                if (!string.IsNullOrEmpty(author.ID) && !string.IsNullOrEmpty(author.Email))
                {
                    string userName = Membership.GetUserNameByEmail(author.Email);
                    if (string.IsNullOrEmpty(userName))
                    {
                        if (Membership.GetUser(author.ID) == null)
                        {
                            Membership.CreateUser(author.ID, Membership.GeneratePassword(6, 1), author.Email);
                        }
                    }
                }
            }
        }

        private void CreateCategories(Category root, IEnumerable<BlogMLCategory> categories)
        {
            foreach (var c in categories)
            {
                var newCat = new Category()
                {
                    Title = c.Title,
                    LastPosted = c.DateModified,
                    Description = c.Description,
                    Path = c.ParentRef,
                    ParentID = root.ID
                };
                pubContext.Categories.Create(newCat);
                categoryReferences.Add(c.ID, newCat);
            }
            pubContext.SaveChanges();
            //Set parent id
            foreach (var key in categoryReferences.Keys)
            {
                var cat = categoryReferences[key];
                if (categoryReferences.ContainsKey(cat.Path))
                {
                    var parentRef = categoryReferences[cat.Path];
                    cat.ParentID = parentRef.ID;
                    cat.Path = TextUtility.Slug(cat.Title);
                }
            }
            pubContext.SaveChanges();
            //set paths
            UpdatePaths(root);
            pubContext.SaveChanges();
            //categoryPool.Clear();
        }

        private void CreatePosts(Category root, IEnumerable<BlogMLPost> posts)
        {
            foreach (var post in posts)
            {
                var article = new Article()
                {
                    Title = post.Title,
                    LastModified = post.DateModified,
                    Posted = post.DateCreated,
                    IsAppoved = post.Approved,
                    Body = post.Content.Text,
                    TotalReads =(int)post.Views
                };

                if (post.HasExcerpt)
                    article.Summary = post.Excerpt.Text;

                if (post.Categories.Count > 0)
                {
                    var relatedCategories = new List<string>();
                    for (int i = 0; i < post.Categories.Count; i++)
                    {
                        var catRef = post.Categories[i];
                        var categoryReference = categoryReferences[catRef.Ref];
                        if (i == 0)
                            article.Category = categoryReference;
                        relatedCategories.Add(categoryReference.ID.ToString());
                    }

                    if (relatedCategories.Count > 0)
                        article.Categories = string.Join(",", relatedCategories.ToArray());
                }
                else
                    article.Category = root;

                article.Category.TotalPosts++;
                article.Pos = pubContext.Articles.GetPosition(article.Category.ID);

                string webName = root.GetRootPath();

                if (string.IsNullOrEmpty(article.Slug))
                    article.Slug = TextUtility.Slug(article.Title);

                pubContext.Articles.Create(article);
                pubContext.SaveChanges(false);

                if (string.IsNullOrEmpty(article.PermaLink))
                {
                    string formattedTitle = article.Slug;
                    string dateStr = article.Posted.ToString("yyyy/MM/dd");
                    article.PermaLink = "/" + (string.IsNullOrEmpty(webName) ? "home" : webName) + "/" + dateStr + "/" + article.ID.ToString() + "/" + formattedTitle + ".html";
                }

                foreach (var cmm in post.Comments)
                {
                    var comment = new Comment()
                    {
                        Article = article,
                        Body = cmm.Content.Text,
                        Email = cmm.UserEMail,
                        IsApproved = cmm.Approved,
                        Posted = cmm.DateCreated,
                        Title = cmm.Title,
                        UserName = cmm.UserName,
                        WebSite = cmm.UserUrl
                    };
                    article.TotalComments++;
                    pubContext.Comments.Create(comment);
                }

                foreach (var trackback in post.Trackbacks)
                {
                    var comment = new Comment() {
                        Article = article,
                        IsApproved = trackback.Approved,
                        Posted = trackback.DateCreated,
                        Title = trackback.Title,
                        UrlReferrer=trackback.Url,
                        WebSite=trackback.Url,
                        IsTrackback=true
                    };
                    article.TotalComments++;
                    pubContext.Comments.Create(comment);
                }
                pubContext.SaveChanges(false);
            }
        }

        private void UpdatePaths(Category parent)
        {
            var children = pubContext.Categories.Children(parent.ID);
            foreach (var child in children)
            {
                child.Path = parent.Path + "/" + child.Path;
                UpdatePaths(child);
            }
        }
    }
}
